package com.xuecheng.content.filter;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreaker;
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.EventObserverRegistry;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.util.TimeUtil;
import com.alibaba.fastjson.JSON;
import com.xuecheng.content.config.resp.RestErrorResponse;
import com.xuecheng.content.enums.RuleEnum;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

/**
 * 全局流量控制的过滤器
 *
 * @author hes
 * 采用sentinel官方提供的网关限流方案，注释调当前过滤器实现
 */
//@Order(2)
//@Component
public class FlowControlFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String s = handleRequest();
        if (s.equals(RuleEnum.REJECT.getKey())) {
            ServerHttpResponse response = exchange.getResponse();
            //构建被流控后的响应
            String jsonString = JSON.toJSONString(new RestErrorResponse(s));
            byte[] bits = jsonString.getBytes(StandardCharsets.UTF_8);
            DataBuffer buffer = response.bufferFactory().wrap(bits);
            response.setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
            response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
            return response.writeWith(Mono.just(buffer));
        }
        return chain.filter(exchange);
    }

    public String handleRequest() {
        Entry entry = null;
        try {
            // 进行流量控制
            entry = SphU.entry("GLOBAL_RESOURCE");
            // 处理请求
            return RuleEnum.PASS.getKey();
        } catch (BlockException ex) {
            //必须调用,以便于close时能够感知到异常发生进行统计,没有调用则使用异常作为熔断的逻辑无法生效
            Tracer.trace(ex);
            // 处理降级情况
            return RuleEnum.REJECT.getKey();
        } finally {
            // 释放 entry 资源
            if (entry != null) {
                entry.exit();
            }
        }
    }
}
